package com.hbisoft.pickit;

import ohos.aafwk.ability.DataAbilityHelper;
import ohos.aafwk.ability.DataUriUtils;
import ohos.app.Context;
import ohos.data.dataability.DataAbilityPredicates;
import ohos.data.resultset.ResultSet;
import ohos.media.photokit.metadata.AVStorage;
import ohos.utils.net.Uri;

import java.io.File;
import java.util.Arrays;
import java.util.List;

public class Utils {

    private static String failReason;

    private static String PATH_DOCUMENT = "document";

    private static String PATH_TREE = "tree";

    private static String DISPLAY_NAME = "_display_name";

    static String errorReason() {
        return failReason;
    }

    /**
     * Main method use to translate uri to file real path
     *
     * @param context context
     * @param uri     file's uri
     * @return the real path of select file
     */
    static String
    getRealPathFromURI_API19(final Context context, final Uri uri) {

        if (isDocumentUri(uri)) {

            if (isExternalStorageDocument(uri)) {
                final String docId = getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                if ("primary".equalsIgnoreCase(type)) {
                    if (split.length > 1) {
                        return context.getFilesDir() + "/" + split[1];
                    } else {
                        return context.getFilesDir() + "/";
                    }
                } else {
                    // Some devices does not allow access to the SD Card using the UID, for example /storage/6551-1152/folder/video.mp4
                    // Instead, we first have to get the name of the SD Card, for example /storage/sdcard1/folder/video.mp4

                    // We first have to check if the device allows this access
                    if (new File("storage" + "/" + docId.replace(":", "/")).exists()) {
                        return "/storage/" + docId.replace(":", "/");
                    }
                    // If the file is not available, we have to get the name of the SD Card, have a look at SDUtils
                    String[] availableExternalStorages = SDUtil.getStorageDirectories(context);
                    String root = "";
                    for (String s : availableExternalStorages) {
                        if (split[1].startsWith("/")) {
                            root = s + split[1];
                        } else {
                            root = s + "/" + split[1];
                        }
                    }
                    if (root.contains(type)) {
                        return "storage" + "/" + docId.replace(":", "/");
                    } else {
                        if (root.startsWith("/storage/") || root.startsWith("storage/")) {
                            return root;
                        } else if (root.startsWith("/")) {
                            return "/storage" + root;
                        } else {
                            return "/storage/" + root;
                        }
                    }
                }

            } else if (isRawDownloadsDocument(uri)) {
                String fileName = getFilePath(context, uri);
                String subFolderName = getSubFolders(uri);

                if (fileName != null) {
                    return context.getFilesDir().toString() + "/Download/" + subFolderName + fileName;
                }
                String id = getDocumentId(uri);

                final Uri contentUri = DataUriUtils.attachId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            } else if (isDownloadsDocument(uri)) {
                String fileName = getFilePath(context, uri);

                if (fileName != null) {
                    return context.getFilesDir().toString() + "/Download/" + fileName;
                }
                String id = getDocumentId(uri);
                if (id.startsWith("raw:")) {
                    id = id.replaceFirst("raw:", "");
                    File file = new File(id);
                    if (file.exists())
                        return id;
                }
                if (id.startsWith("raw%3A%2F")) {
                    id = id.replaceFirst("raw%3A%2F", "");
                    File file = new File(id);
                    if (file.exists())
                        return id;
                }
                final Uri contentUri = DataUriUtils.attachId(Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
                return getDataColumn(context, contentUri, null, null);
            } else if (isMediaDocument(uri)) {
                final String docId = getDocumentId(uri);
                final String[] split = docId.split(":");
                final String type = split[0];

                Uri contentUri = null;
                if ("image".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI;
                } else if ("video".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI;
                } else if ("audio".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[1]
                };

                return getDataColumn(context, contentUri, selection, selectionArgs);
            }
        } else if ("content".equalsIgnoreCase(uri.getScheme())) {
            if (isGooglePhotosUri(uri)) {
                return uri.getLastPath();
            }
            String path = null;
            try {
                final String[] split = uri.toString().split("/");
                final String type = split[split.length - 3];
                Uri contentUri = null;
                if ("image".equalsIgnoreCase(type) || "images".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Images.Media.EXTERNAL_DATA_ABILITY_URI;
                } else if ("video".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Video.Media.EXTERNAL_DATA_ABILITY_URI;
                } else if ("audio".equalsIgnoreCase(type)) {
                    contentUri = AVStorage.Audio.Media.EXTERNAL_DATA_ABILITY_URI;
                }

                final String selection = "_id=?";
                final String[] selectionArgs = new String[]{
                        split[split.length - 1]
                };
                path = getDataColumn(context, contentUri, selection, selectionArgs);

            } catch (Exception e) {
                e.printStackTrace();
            }
            return path;
//            if (getDataColumn(context, realUri, null, null) == null) {
//                failReason = "dataReturnedNull";
//            }
//            return getDataColumn(context, realUri, null, null);
        } else if ("file".equalsIgnoreCase(uri.getScheme())) {
            return uri.getDecodedPath();
        }

        return null;
    }

    /**
     * Test if the given URI represents
     * @param uri
     * @return boolean
     */
    private static boolean isDocumentUri(Uri uri) {
        if (isContentUri(uri)) {
            final List<String> paths = uri.getDecodedPathList();
            if (paths.size() == 2) {
                return PATH_DOCUMENT.equals(paths.get(0));
            } else if (paths.size() == 4) {
                return PATH_TREE.equals(paths.get(0)) && PATH_DOCUMENT.equals(paths.get(2));
            }
        }
        return false;
    }

    private static boolean isContentUri(Uri uri) {
        return uri != null && "content".equals(uri.getScheme());
    }

    /**
     * Extract the ID from the given URI.
     * @param documentUri
     * @return String
     * @throws IllegalArgumentException
     */
    private static String getDocumentId(Uri documentUri) {
        final List<String> paths = documentUri.getDecodedPathList();
        if (paths.size() >= 2 && PATH_DOCUMENT.equals(paths.get(0))) {
            return paths.get(1);
        }
        if (paths.size() >= 4 && PATH_TREE.equals(paths.get(0))
                && PATH_DOCUMENT.equals(paths.get(2))) {
            return paths.get(3);
        }
        throw new IllegalArgumentException("Invalid URI: " + documentUri);
    }

    private static String getSubFolders(Uri uri) {
        String replaceChars = String.valueOf(uri).replace("%2F", "/").replace("%20", " ").replace("%3A", ":");
        String[] bits = replaceChars.split("/");
        String sub5 = bits[bits.length - 2];
        String sub4 = bits[bits.length - 3];
        String sub3 = bits[bits.length - 4];
        String sub2 = bits[bits.length - 5];
        String sub1 = bits[bits.length - 6];
        if (sub1.equals("Download")) {
            return sub2 + "/" + sub3 + "/" + sub4 + "/" + sub5 + "/";
        } else if (sub2.equals("Download")) {
            return sub3 + "/" + sub4 + "/" + sub5 + "/";
        } else if (sub3.equals("Download")) {
            return sub4 + "/" + sub5 + "/";
        } else if (sub4.equals("Download")) {
            return sub5 + "/";
        } else {
            return "";
        }
    }

    private static String getDataColumn(Context context, Uri uri, String selection, String[] selectionArgs) {
        ResultSet cursor = null;
        final String column = "_data";
        final String[] projection = {column};
        try {
            DataAbilityPredicates predicates = new DataAbilityPredicates(selection);
            if (selectionArgs != null && selectionArgs.length > 0) {
                predicates.setWhereArgs(Arrays.asList(selectionArgs));
            } else {
                predicates.setWhereArgs(null);
            }
            cursor = DataAbilityHelper.creator(context).query(uri, projection, predicates);
            if (cursor != null && cursor.goToFirstRow()) {
                final int index = cursor.getColumnIndexForName(column);
                return cursor.getString(index);
            }
        } catch (Exception e) {
            failReason = e.getMessage();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }


    private static String getFilePath(Context context, Uri uri) {
        ResultSet cursor = null;
        final String[] projection = {DISPLAY_NAME};
        try {
            cursor = DataAbilityHelper.creator(context).query(uri, projection, new DataAbilityPredicates());
            if (cursor != null && cursor.goToFirstRow()) {
                final int index = cursor.getColumnIndexForName(DISPLAY_NAME);
                return cursor.getString(index);
            }
        } catch (Exception e) {
            failReason = e.getMessage();
        } finally {
            if (cursor != null)
                cursor.close();
        }
        return null;
    }


    private static boolean isExternalStorageDocument(Uri uri) {
        return "com.android.externalstorage.documents".equals(uri.getDecodedAuthority());
    }


    private static boolean isDownloadsDocument(Uri uri) {
        return "com.android.providers.downloads.documents".equals(uri.getDecodedAuthority());
    }

    private static boolean isRawDownloadsDocument(Uri uri) {
        String uriToString = String.valueOf(uri);
        return uriToString.contains("com.android.providers.downloads.documents/document/raw");
    }

    private static boolean isMediaDocument(Uri uri) {
        return "com.android.providers.media.documents".equals(uri.getDecodedAuthority());
    }


    private static boolean isGooglePhotosUri(Uri uri) {
        return "com.google.android.apps.photos.content".equals(uri.getDecodedAuthority());
    }

}
